package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.util.WeChatUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

/**
 * (PrizeDrawResult)表服务实现类
 *
 * @author 王伟成
 * @since 2023-09-12 14:55:46
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PrizeDrawResultServiceImpl implements PrizeDrawResultService {

    private final PrizeDrawResultDao prizeDrawResultDao;

    private final ActivityBasicsService activityBasicsService;

    private final UserPrizeDrawRecordsDao userPrizeDrawRecordsDao;

    private final ActivityAwardDao activityAwardDao;

    private final PrizeDrawActivitySettleRecordsDao prizeDrawActivitySettleRecordsDao;

    private final UserInfoDao userInfoDao;

    private final IdcardInfoDao idcardInfoDao;

    private final UserEquityPropsDao userEquityPropsDao;

    private final PrizeDrawActivityPoolDao prizeDrawActivityPoolDao;

    private final PrizeDrawActivityRewardsDao prizeDrawActivityRewardsDao;

    private final UserPrizeDrawRecordsService userPrizeDrawRecordsService;

    private final CarveUpPoolService carveUpPoolService;
    private final UserWalletService userWalletService;
    private final UserAssetsService userAssetsService;
    private final EquityPropsDao equityPropsDao;
    private final UserEquityPropsService userEquityPropsService;
    private final ActivityBasicsDao activityBasicsDao;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void arrangeFiveResult() {
        HttpRequest httpRequest = HttpRequest.get("https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=350133&provinceId=0&isVerify=1&termLimits=30");
        String result = httpRequest.execute().body();

        // 结果集直接序列化
        JSONObject data = JSONObject.parseObject(result, JSONObject.class);
        // 获取value字段中的数据,他里面包含了很多
        JSONObject dataValue = JSONObject.parseObject(data.getString("value"), JSONObject.class);
        // 获取最新一期的开奖数据
        JSONObject dataValueLastPoolDraw = JSONObject.parseObject(dataValue.getString("lastPoolDraw"), JSONObject.class);
        String lotteryDrawNum = dataValueLastPoolDraw.getString("lotteryDrawNum");
        String lotteryDrawResult = dataValueLastPoolDraw.getString("lotteryDrawResult");
        String lotteryDrawTime = dataValueLastPoolDraw.getString("lotteryDrawTime");
        PrizeDrawResult prizeDrawResult = new PrizeDrawResult();
        prizeDrawResult.setLotteryDrawResult(Convert.toStr(lotteryDrawResult.replace(" ", "")));
        prizeDrawResult.setLotteryDrawResultVar(lotteryDrawResult);
        prizeDrawResult.setLotteryDrawTime(lotteryDrawTime.replace("-", ""));
        prizeDrawResult.setLotteryDrawNum(lotteryDrawNum);
        String[] s = lotteryDrawResult.split(" ");
        if (s.length!=5) {
            return;
        }
        prizeDrawResult.setV1(Convert.toInt(s[0]));
        prizeDrawResult.setV2(Convert.toInt(s[1]));
        prizeDrawResult.setV3(Convert.toInt(s[2]));
        prizeDrawResult.setV4(Convert.toInt(s[3]));
        prizeDrawResult.setV5(Convert.toInt(s[4]));
        PrizeDrawResult byLotteryDrawNumAndLotteryDrawTime = prizeDrawResultDao.getByLotteryDrawNumAndLotteryDrawTime(lotteryDrawNum, lotteryDrawTime.replace("-", ""));
        if (BeanUtil.isEmpty(byLotteryDrawNumAndLotteryDrawTime)) {
            // 不存在则新增.
            prizeDrawResult.insert();
            // 对对应的活动项进行更改.
            activityBasicsService.lottery(lotteryDrawTime.replace("-", ""), prizeDrawResult.getId(), prizeDrawResult.getLotteryDrawResult());
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void drawLottery(ActivityBasics activityBasics) {
        // 根据活动id把对应重复的奖励奖券用户设置为未中奖
        userPrizeDrawRecordsDao.losingLottery(activityBasics.getId());
        Integer byActivityBasicsId = activityAwardDao.getByActivityBasicsIdGroupByLv(activityBasics.getId());
        // 奖励为空的时候这个奖励就不在发放了.
        if (byActivityBasicsId==null || byActivityBasicsId<=0) {
            return;
        }
        // 根据活动奖励挨个向下对比获取 取对应的奖励后结束 如果不满足的话则进行倒转进行继续获取对应的数量
        // 比方: 有10个奖励,奖励分过组以后,正向获取了9个,那么就要再逆向,在获取一个 让后合并排序.才是正确的用户数据.
        List<UserPrizeDrawRecords> userPrizeDrawRecords = userPrizeDrawRecordsDao.winAPrizeLottery(activityBasics.getId(), Convert.toInt(activityBasics.getLotteryDrawResult()),byActivityBasicsId, Boolean.FALSE);
        // 两个是否相符,如果不符的话,则进行翻转后,在请求一次.把数据合并掉
        if (userPrizeDrawRecords.size() != byActivityBasicsId) {
            List<UserPrizeDrawRecords> overturnUserPrizeDrawRecords = userPrizeDrawRecordsDao.winAPrizeLottery(activityBasics.getId(), Convert.toInt(activityBasics.getLotteryDrawResult()),byActivityBasicsId-userPrizeDrawRecords.size(), Boolean.TRUE);
            // 合并
            userPrizeDrawRecords.addAll(overturnUserPrizeDrawRecords);
        }

        // userPrizeDrawRecords 在以上方法走完以后,就变成了完整的列表榜单,让后循环去获取对应的榜单
        // 第一个就获取第一名 第二个就获取第二名以此类推,让后标记成已中奖并且对他进行修改,且组装奖励数据,写如到待发的库里
        // 待发的库中的发放时间设定到当天推迟一天的晚上8点.
        List<PrizeDrawActivitySettleRecords> list = new ArrayList<>();
        for (int i = 0; i < userPrizeDrawRecords.size(); i++) {
            // 修改中奖用户的彩票数据
            // 获取奖励,没有结束本次循环.
            List<ActivityAward> byactivityBasicsIdAndAwardLv = activityAwardDao.getByactivityBasicsIdAndAwardLv(activityBasics.getId(), i + 1);
            if (CollUtil.isEmpty(byactivityBasicsIdAndAwardLv)) {
                continue;
            }
            StringJoiner stringJoiner = new StringJoiner(",");
            // 循环拼接奖励
            byactivityBasicsIdAndAwardLv.forEach(activityAward -> {
                stringJoiner.add(StrUtil.format("{}*{}", activityAward.getPropName(), activityAward.getPropNum()));
            });
            UserPrizeDrawRecords resultData = userPrizeDrawRecords.get(i);
            resultData.setIsWinPrizeLottery(2);
            // 排名,循环是从下标0开始的
            resultData.setGuessType(i+1);
            // 奖励等级是一样的
            resultData.setTypeName(byactivityBasicsIdAndAwardLv.get(0).getAwardLvName());
            resultData.updateById();
            // 组装中奖用户的彩票奖励
            UserInfo userInfo = userInfoDao.getById(resultData.getUserId());
            IdcardInfo byUserIdAndIsPass = idcardInfoDao.getByUserIdAndIsPass(resultData.getUserId());

            PrizeDrawActivitySettleRecords prizeDrawActivitySettleRecords = new PrizeDrawActivitySettleRecords();
            prizeDrawActivitySettleRecords.setActivityId(activityBasics.getId());
            prizeDrawActivitySettleRecords.setActivityType(PrizeDrawActivityTypeEnum.GUESSING_ACTIVITY);
            prizeDrawActivitySettleRecords.setLinkRewardsId(activityBasics.getId());
            prizeDrawActivitySettleRecords.setRewards(stringJoiner.toString());
            prizeDrawActivitySettleRecords.setUserId(resultData.getUserId());
            prizeDrawActivitySettleRecords.setUserRecordsId(resultData.getId());
            prizeDrawActivitySettleRecords.setLotteryDrawResultVar(activityBasics.getLotteryDrawResult());
            prizeDrawActivitySettleRecords.setUserTel(userInfo.getUserTel());
            prizeDrawActivitySettleRecords.setName(byUserIdAndIsPass.getName());
            prizeDrawActivitySettleRecords.setGuessType(i+1);
            prizeDrawActivitySettleRecords.setTypeName(byactivityBasicsIdAndAwardLv.get(0).getAwardLvName());
            prizeDrawActivitySettleRecords.setStatus(PrizeDrawActivitySettleStatisEnum.UNISSUED);
            prizeDrawActivitySettleRecords.setIsSettle(Boolean.FALSE);
            prizeDrawActivitySettleRecords.setUserLotteryDrawResult(resultData.getLotteryDrawResult());
            list.add(prizeDrawActivitySettleRecords);
        }
        prizeDrawActivitySettleRecordsDao.saveBatch(list);

        // 把所有未开奖的,全部设置为未中奖,因为已经开完了.
        userPrizeDrawRecordsDao.losingLotteryAll(activityBasics.getId());
        // 设置为已结算
        activityBasics.setIsSettle(Boolean.TRUE);
        activityBasics.updateById();
        // 把该期的抽奖记录统计数据做落库记录.
        // 抽奖人数  抽奖次数  已发放的奖券 已使用的奖券.


        // 抽奖人数
        Long numberPeopleDrawn = userPrizeDrawRecordsDao.numberPeopleDrawn(activityBasics.getId());
        // 抽奖次数
        Long numberDraws = userPrizeDrawRecordsDao.numberDraws(activityBasics.getId());
        HistoryPrizeDrawActivityDetailsLog historyPrizeDrawActivityDetailsLog = new HistoryPrizeDrawActivityDetailsLog();
        historyPrizeDrawActivityDetailsLog.setActivityId(activityBasics.getId());
        historyPrizeDrawActivityDetailsLog.setActivityType(PrizeDrawActivityTypeEnum.GUESSING_ACTIVITY);
        historyPrizeDrawActivityDetailsLog.setAttendUserCount(numberPeopleDrawn);
        historyPrizeDrawActivityDetailsLog.setAttendCount(numberDraws);
        Integer lotteryTicketDistributionStatistics = userEquityPropsDao.lotteryTicketDistributionStatistics(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), null);
        historyPrizeDrawActivityDetailsLog.setEquityCount(Convert.toLong(lotteryTicketDistributionStatistics));
        Integer userLotteryTicketDistributionStatistics = userEquityPropsDao.lotteryTicketDistributionStatisticsEmploy(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), 1);
        historyPrizeDrawActivityDetailsLog.setUseEquityCount(Convert.toLong(userLotteryTicketDistributionStatistics));
        historyPrizeDrawActivityDetailsLog.insert();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void divideUpTheLottery(ActivityBasics activityBasics) {
        Long lotteryResultId = activityBasics.getLotteryResultId();
        if (ObjectUtil.isNull(lotteryResultId) || lotteryResultId.intValue() == 0) {
            WeChatUtil.sendWeChatMessage(StrUtil.format("瓜分活动开奖失败,开奖号码为空,活动id:{}", activityBasics.getId()));
            return;
        }

        PrizeDrawResult prizeDrawResult = prizeDrawResultDao.getById(lotteryResultId);
        if (ObjectUtil.isNull(prizeDrawResult)) {
            WeChatUtil.sendWeChatMessage(StrUtil.format("瓜分活动开奖失败,开奖号码为空,活动id:{},开奖号码表id:{}", activityBasics.getId(), lotteryResultId));
            return;
        }

        //本次活动累计金额
        BigDecimal AccumulatedaAmount = prizeDrawActivityPoolDao.getSumAmountByActivityId(activityBasics.getId());
        //本次活动的初始金额
        BigDecimal initialAmount = activityBasics.getInitPoolReserve();
        //本期总金额
        BigDecimal sumAmount = initialAmount.add(AccumulatedaAmount);
        //预留金额
        BigDecimal reserveAmount = sumAmount.multiply(activityBasics.getPrizePoolReserve().movePointLeft(2));
        //发放总金额
        BigDecimal bonusAmount = sumAmount.subtract(reserveAmount);
        log.info("本次活动累计金额:{},初始金额:{},本期总金额:{},预留金额:{},发放总金额:{}",AccumulatedaAmount.stripTrailingZeros().toPlainString(), initialAmount.stripTrailingZeros().toPlainString(),sumAmount.stripTrailingZeros().toPlainString(),reserveAmount.stripTrailingZeros().toPlainString(),bonusAmount.stripTrailingZeros().toPlainString());
        //统计本期数据
        HistoryPrizeDrawActivityDetailsLog historyPrizeDrawActivityDetailsLog = new HistoryPrizeDrawActivityDetailsLog();
        historyPrizeDrawActivityDetailsLog.setAccumulatedAmount(sumAmount);
        historyPrizeDrawActivityDetailsLog.setReserveAmount(reserveAmount);
        historyPrizeDrawActivityDetailsLog.setDisbursementAmount(bonusAmount);

        //初始化所有中奖用户
        ArrayList<Long> notInIds = Lists.newArrayList();
        BigDecimal unissuedAmount = BigDecimal.ZERO;
        //本期要发放的奖项列表
        List<PrizeDrawActivityRewards> rewardsList = prizeDrawActivityRewardsDao.getListByActivityId(activityBasics.getId());
        for (PrizeDrawActivityRewards prizeDrawActivityRewards : rewardsList) {
            String name = prizeDrawActivityRewards.getName();
            //获取此奖项的中奖号码和人数
            List<UserPrizeDrawRecords> list = userPrizeDrawRecordsService.getUserLotteryListByActivityIdAndTypeAndNumber(activityBasics.getId(), prizeDrawActivityRewards.getType(), prizeDrawResult.getV1(), prizeDrawResult.getV2(), prizeDrawResult.getV3(), prizeDrawResult.getV4(), prizeDrawResult.getV5(),notInIds);
            //计算此奖项的中奖金额
            BigDecimal multiply = bonusAmount.multiply(prizeDrawActivityRewards.getScale());

            if(list.size() ==0){//如果没有人中奖 则累计到预留奖池
                unissuedAmount = unissuedAmount.add(multiply);
                continue;
            }
            //有中奖的
            //则按照人数分配奖金
            BigDecimal amount = multiply.divide(Convert.toBigDecimal(list.size()), 2, BigDecimal.ROUND_DOWN);
            //初始化每个奖项的用户号码表id
            ArrayList<Long> ids = Lists.newArrayList();

            for (UserPrizeDrawRecords userPrizeDrawRecords : list) {
                PrizeDrawActivitySettleRecords prizeDrawActivitySettleRecords = new PrizeDrawActivitySettleRecords();
                prizeDrawActivitySettleRecords.setActivityId(activityBasics.getId());
                prizeDrawActivitySettleRecords.setActivityType(activityBasics.getType());
                prizeDrawActivitySettleRecords.setAmount(amount);
                prizeDrawActivitySettleRecords.setLinkRewardsId(prizeDrawActivityRewards.getId());
                prizeDrawActivitySettleRecords.setUserId(userPrizeDrawRecords.getUserId());
                prizeDrawActivitySettleRecords.setUserRecordsId(userPrizeDrawRecords.getId());
                prizeDrawActivitySettleRecords.setLotteryDrawResultVar(StrUtil.format("{}{}{}{}{}",prizeDrawResult.getV1(),prizeDrawResult.getV2(),prizeDrawResult.getV3(),prizeDrawResult.getV4(),prizeDrawResult.getV5()));
                prizeDrawActivitySettleRecords.setUserLotteryDrawResult(userPrizeDrawRecords.getLotteryDrawResult());
                UserInfo user = userInfoDao.getById(userPrizeDrawRecords.getUserId());
                prizeDrawActivitySettleRecords.setUserTel(user.getUserTel());

                IdcardInfo idcardInfo = idcardInfoDao.findLastOneByUserIdAndIsPass(userPrizeDrawRecords.getUserId());
                prizeDrawActivitySettleRecords.setName(idcardInfo.getName());

                prizeDrawActivitySettleRecords.setType(prizeDrawActivityRewards.getType());
                prizeDrawActivitySettleRecords.setTypeName(name);
                prizeDrawActivitySettleRecords.setStatus(PrizeDrawActivitySettleStatisEnum.UNISSUED);
                prizeDrawActivitySettleRecords.setIsSettle(Boolean.FALSE);
                prizeDrawActivitySettleRecords.insert();

                ids.add(userPrizeDrawRecords.getId());

            }

            notInIds.addAll(ids);
            //修改用户号码表位中奖
            userPrizeDrawRecordsService.updateWinPrizeLotteryAndTypeNameByIds(activityBasics.getId(), ids, prizeDrawActivityRewards.getType(), name);
        }
        //处理未中奖的用户
        userPrizeDrawRecordsService.updateLosingLotteryAndTypeNameByIds(activityBasics.getId(),notInIds);
        BigDecimal residualAmount= reserveAmount.add(unissuedAmount);
        //处理剩余奖金
        carveUpPoolService.addPoolAmountAndSubFreezeAmount(activityBasics.getId(),residualAmount,activityBasics.getInitPoolReserve());

        activityBasicsDao.updateLotteryStatusAndIsSettleById(activityBasics.getId(),1,Boolean.TRUE);


        historyPrizeDrawActivityDetailsLog.setActivityId(activityBasics.getId());
        historyPrizeDrawActivityDetailsLog.setActivityType(activityBasics.getType());
        historyPrizeDrawActivityDetailsLog.setAttendUserCount(userPrizeDrawRecordsDao.numberPeopleDrawn(activityBasics.getId()));
        historyPrizeDrawActivityDetailsLog.setAttendCount(userPrizeDrawRecordsDao.numberDraws(activityBasics.getId()));
        historyPrizeDrawActivityDetailsLog.setEquityCount(userEquityPropsDao.lotteryTicketDistributionStatistics(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), null).longValue());
        historyPrizeDrawActivityDetailsLog.setUseEquityCount(userEquityPropsDao.lotteryTicketDistributionStatisticsEmploy(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), 1).longValue());


        historyPrizeDrawActivityDetailsLog.setUnissuedAmount(unissuedAmount);
        historyPrizeDrawActivityDetailsLog.setResidualAmount(residualAmount);
        historyPrizeDrawActivityDetailsLog.insert();
    }

    @Override
    public List<PrizeDrawActivitySettleRecords> getListByIsSettleAndStatus() {
        return prizeDrawActivitySettleRecordsDao.getListByIsSettleAndStatus();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void distributeWinningPrizes(PrizeDrawActivitySettleRecords prizeDrawActivitySettleRecords) {
        ActivityBasics activityBasics = activityBasicsService.getById(prizeDrawActivitySettleRecords.getActivityId());

        if(prizeDrawActivitySettleRecords.getActivityType() == PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY){//瓜分
            //加钱(红包/原石)
            Assert.isTrue(userWalletService.addAmountByUserId(prizeDrawActivitySettleRecords.getUserId(),prizeDrawActivitySettleRecords.getAmount(), UserBalanceTypeEnum.PAY_BALANCE,activityBasics.getNameActivity() + prizeDrawActivitySettleRecords.getTypeName(), WalletDetailTypeEnum.CARVE_UP),()->new GlobalRunTimeException("加钱失败!"));
        }else if (prizeDrawActivitySettleRecords.getActivityType() == PrizeDrawActivityTypeEnum.GUESSING_ACTIVITY){//竞猜
            //发放奖励
            List<ActivityAward> byactivityBasicsIdAndAwardLv = activityAwardDao.getByactivityBasicsIdAndAwardLv(prizeDrawActivitySettleRecords.getActivityId(), prizeDrawActivitySettleRecords.getGuessType());
            for (ActivityAward activityAward : byactivityBasicsIdAndAwardLv) {
                switch (activityAward.getPropType().intValue()) {
                    case 1:
                        userAssetsService.addIntegralByUserId(NumberUtil.toBigDecimal(activityAward.getPropNum()), prizeDrawActivitySettleRecords.getUserId(), CoinCategoryEnum.INTEGRAL, AssetChangeLogEnum.GUESSING_GAME, prizeDrawActivitySettleRecords.getId(), activityBasics.getNameActivity() + prizeDrawActivitySettleRecords.getTypeName());
                        break;
                    case 2:
                        EquityProps equityProps = equityPropsDao.getById(activityAward.getPropId());
                        Assert.notNull(equityProps,()->new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST));
                        userEquityPropsService.addEquityPropsByUser(equityProps,prizeDrawActivitySettleRecords.getUserId(), UserEquityPropsGetTypeEnum.GUESSING_GAME,activityAward.getPropNum(),activityBasics.getNameActivity() + prizeDrawActivitySettleRecords.getTypeName(),prizeDrawActivitySettleRecords.getId()
                                ,BigDecimal.ZERO,UserEquityPropsGetTypeEnum.GUESSING_GAME,prizeDrawActivitySettleRecords.getId());
                        break;
                }
            }

        }else{
            WeChatUtil.sendWeChatMessage(StrUtil.format("记录表id:{},发放奖励失败,活动类型错误", prizeDrawActivitySettleRecords.getId()));
        }

        Assert.isTrue(prizeDrawActivitySettleRecordsDao.updateIsSettleAndStatusById(prizeDrawActivitySettleRecords.getId()),()-> new GlobalRunTimeException("修改失败"));

    }
}
